﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace ABFW
{
    /// <summary>
    /// 主流程:
    ///     一个场景中多个AssetBundle的管理
    ///  Description:
    ///     功能:
    ///         1：获取AB包之间的依赖与引用关系
    ///         2：管理AssetBundle包之间的自动连锁(递归)加锁机制
    /// 
    /// </summary>
    public class MultiABMgr
    {
        //(下层)引用类：单个AB包加载实例
        private SingleABLoader _CurrntSingleABLoader;
        //"AB包实现类" 缓存集合(作用： 缓存AB包,防止重复加载,"AB包缓存集合")
        private Dictionary<string, SingleABLoader> _DicSingleABLoaderCache;
        //当前场景(调试使用)
        private string _CurrentScenesName;
        //当前AssetBundle 名称
        private string _CurrentABName;
        //AB包与对应的依赖关系集合
        private Dictionary<string, ABRelation> _DicABRelation;
        //委托： 所有AB包加载完毕
        private DelLoadComplete _LoadAllPackageCompleteHandle;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="scenesName">场景名称</param>
        /// <param name="abName">AB包名称</param>
        /// <param name="loadAllABPackCompleteHandle">(委托)是否调用完成</param>
        public MultiABMgr(string scenesName,string abName,DelLoadComplete loadAllABPackCompleteHandle)
        {
            _CurrentScenesName = scenesName;
            _CurrentABName = abName;
            _DicSingleABLoaderCache = new Dictionary<string, SingleABLoader>();
            _DicABRelation = new Dictionary<string, ABRelation>();
            //委托
            _LoadAllPackageCompleteHandle = loadAllABPackCompleteHandle;
        }

        /// <summary>
        /// 完成指定AB包调用
        /// </summary>
        /// <param name="abName">AB包名</param>
        private void CompleteLoadAB(string abName)
        {
            if (abName.Equals(_CurrentABName))
            {
                if(_LoadAllPackageCompleteHandle!= null)
                {
                    _LoadAllPackageCompleteHandle(abName);
                }
            }
        }

        /// <summary>
        /// 加载AB包,DFS递归调用
        /// </summary>
        /// <param name="abName">AB包名</param>
        /// <returns></returns>
        public IEnumerator LoadAssetBundle(string abName)
        {
            //AB包关系建立
            if (!_DicABRelation.ContainsKey(abName))
            {
                ABRelation abRelationObj = new ABRelation(abName);
                _DicABRelation.Add(abName, abRelationObj);
            }
            ABRelation tmpABRelationObj = _DicABRelation[abName];

            //得到指定AB包所有的依赖关系(查询Manifest清单文件)
            string[] strDependenceArray = ABManifestLoader.Instance.RetrivalDependence(abName);
            foreach (string item_Dependence in strDependenceArray)
            {
                //添加依赖项
                tmpABRelationObj.AddDependence(item_Dependence);
                //添加引用项...协程(异步?)方法(递归调用)
                yield return LoadReference(item_Dependence, abName);
            }

            //真正加载AB包
            if (_DicSingleABLoaderCache.ContainsKey(abName))
            {
                yield return _DicSingleABLoaderCache[abName].LoadAssetBundle();
            }else
            {
                _CurrntSingleABLoader = new SingleABLoader(abName,CompleteLoadAB);
                //将单包加入到缓存集合
                _DicSingleABLoaderCache.Add(abName, _CurrntSingleABLoader);
                //加载单包
                yield return _CurrntSingleABLoader.LoadAssetBundle();
            }


            //...

            yield return null;
        }


        private IEnumerator LoadReference(string abName,string refABName)
        {
            //AB包已经加载(从底层往上走,加载过证明底层也加载过了,所以直接引用就行了)
            if (_DicABRelation.ContainsKey(abName))
            {
                ABRelation tmpABRelationObj = _DicABRelation[abName];
                //添加AB包引用关系(被依赖)
                tmpABRelationObj.AddReference(refABName);
            }else
            {
                //没有加载过的话,需要在这里进行加载,添加到缓存,并且直接递归寻找下一层(依赖)
                ABRelation tmpABRelationObj = new ABRelation(abName);
                tmpABRelationObj.AddReference(refABName);
                //添加到缓存中
                _DicABRelation.Add(abName, tmpABRelationObj);

                //开始加载依赖的包(递归调用)
                yield return LoadAssetBundle(abName);
            }
        }

        /// <summary>
        /// 加载(AB包中)资源
        /// </summary>
        /// <param name="abName"></param>
        /// <param name="assetName"></param>
        /// <param name="isCache"></param>
        /// <returns></returns>
        public UnityEngine.Object LoadAsset(string abName,string assetName,bool isCache)
        {
            foreach(string item_abName in _DicSingleABLoaderCache.Keys)
            {
                if (abName == item_abName)
                {
                    return _DicSingleABLoaderCache[item_abName].LoadAsset(assetName, isCache);
                }
            }
            Debug.LogError(GetType() + "/LoadAsset()/找不到AssetBundle包.无法加载资源,请检查");
            return null;
        }

        /// <summary>
        /// 释放本场景中所有资源,建议场景与场景间转换时进行执行
        /// </summary>
        public void DisposeAllAsset()
        {
            try
            {
                //主义是方所有加载过的AssetBundle包中的资源
                foreach (SingleABLoader item in _DicSingleABLoaderCache.Values)
                {
                    item.DisposeAll();
                }
            }
            finally
            {
                //彻底释放所有资源
                _DicSingleABLoaderCache.Clear();
                _DicSingleABLoaderCache = null;

                //释放其他对象占用资源
                _DicABRelation.Clear();
                _DicABRelation = null;
                _CurrentABName = null;
                _CurrentScenesName = null;
                _LoadAllPackageCompleteHandle = null;

                //卸载没有使用到的资源
                Resources.UnloadUnusedAssets();
                //强制垃圾收集
                System.GC.Collect();
            }

        }
    }
}
